package cc.iits.demo.crane.service.core;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cglib.beans.BeanCopier;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 通用Service
 * 1.object转换
 * @param <M>
 * @param <T>
 * @author 易俊
 */
public class CraneServiceImpl<M extends BaseMapper<T>, T> extends ServiceImpl<M, T> {

    private final static Logger logger = LoggerFactory.getLogger(CraneServiceImpl.class);
    private final static Map<String, BeanCopier> copiers = new HashMap<>();
    private final static String keyFormat = "%s-%s";

    protected <T, M> List<T> change(List<M> list, Class<T> targetClass) {
        return change(list, targetClass, false);
    }

    protected <T, M> List<T> change(List<M> list, Class<T> targetClass, boolean useConverter) {
        if (null == list) {
            return null;
        }
        List<T> values = new ArrayList<>();
        for (M entity : list) {
            values.add(change(entity, targetClass, useConverter));
        }
        return values;
    }

    protected <T, M> T change(M entity, Class<T> targetClass) {
        return change(entity, targetClass, false);
    }

    protected <T, M> T change(M entity, Class<T> targetClass, boolean useConverter) {
        if (null == entity) {
            return null;
        }
        BeanCopier copier = getCopier(entity.getClass(), targetClass, useConverter);
        T inst = instance(targetClass);
        copier.copy(entity, inst, null);
        return inst;
    }

    private static synchronized BeanCopier getCopier(Class source, Class target, boolean useConverter) {
        String key = String.format(keyFormat, useConverter, source.getName());
        if (!copiers.containsKey(key)) {
            copiers.put(key, BeanCopier.create(source, target, useConverter));
        }
        return copiers.get(key);
    }

    private <T> T instance(Class<T> clazz) {
        try {
            T inst = clazz.newInstance();
            return inst;
        } catch (IllegalAccessException | InstantiationException e) {
            logger.error("new instance error . class: {}", clazz.getName());
            throw new RuntimeException(e);
        }
    }
}
